#ifndef _TIMED_EVENT_H
#define _TIMED_EVENT_H

enum EventFlags
{
	EVENT_CAST_SPELL		= 0x01,
	EVENT_TAXI_UPDATE		= 0x02,
	EVENT_EXPRESS_UPDATE	= 0x03,
};

class DLL_EXPORT Callback abstract
{
public:
	virtual void Execute() = 0;
};

template<class T>
class DLL_EXPORT CallbackP0 : public Callback
{
	typedef void (T::*proc)();
	proc exec;
	T* inst;
public:
	void Execute() { return (inst->*exec)(); }
	CallbackP0(void (T::*p)(), T* ins) : exec(p), inst(ins)
	{
	}
};

template<class T, class P1>
class DLL_EXPORT CallbackP1 : public Callback
{
	typedef void (T::*proc)(P1);
	proc exec;
	T* inst;
	P1 p1;
public:
	void Execute() { return (inst->*exec)(p1); }
	CallbackP1(void (T::*p)(P1), T* ins, P1 pa1) : exec(p), inst(ins), p1(pa1)
	{
	}
};

class TimedEvent;
class EventHolder;

class DLL_EXPORT EventWorker
{
protected:
	Mutex lock;
	set<EventHolder*> m_activeholders;
	virtual void WorkHolders() = 0;
public:
	EventWorker() {}
	void RemoveHolder(EventHolder* holder) 
	{
		lock.Acquire();
		m_activeholders.erase(holder); 
		lock.Release();
	}
	void AddHolder(EventHolder* holder)
	{
		lock.Acquire();
		if(m_activeholders.find(holder) != m_activeholders.end())
		{
			lock.Release();
			return;
		}
		m_activeholders.insert(holder);
		lock.Release();
	}
};

class DLL_EXPORT EventHolder
{
	Mutex m_evmutex;
	set<TimedEvent*> m_events;
	EventWorker* m_worker;
	friend class EventWorker;
public:
	EventHolder() : m_worker(0)
	{
	}
	virtual ~EventHolder()
	{
		if(m_worker)
			m_worker->RemoveHolder(this);
		m_worker = 0;
	}
	void AddEvent(TimedEvent* ev)
	{
		if(m_worker)
			m_worker->AddHolder(this);
		ScopedLock<Mutex> l(m_evmutex);
		m_events.insert(ev);
	}
	virtual bool Update(ui32 time);
	void SetEventWorker(EventWorker* worker) 
	{
		if(m_worker)
			m_worker->RemoveHolder(this);
		m_worker = worker; 
	}

	void PushToWorker()
	{
		if(m_worker)
			m_worker->AddHolder(this);
	}

	void PopFromWorker()
	{
		if(m_worker)
			m_worker->RemoveHolder(this);
	}

	void RemoveEvent(TimedEvent* te);
	void RemoveEventsByType(ui32 type);
	void RemoveEvents();

	void Unload();
	void ForceRegister(EventWorker* registerer);
};

class DLL_EXPORT TimedEvent
{
	friend class EventHolder;
	Callback* m_cb;
	ui32 m_ref;
	ui32 m_inref;
	ui32 m_time;
	ui32 m_lastup;
	ui32 type;
	ui32 m_curtime;
public:
	TimedEvent(Callback* cb, ui32 interval, ui32 count, ui32 type = 0);
	bool DecRef();
};

#endif